package simulacao;

import simulacao.util.estruturas.*;
import java.lang.Void;
import simulacao.modelo.veiculos.Veiculo;
import javafx.util.Math;
import simulacao.SimulationView;
import simulacao.util.Util;
import simulacao.util.SaidaPersonalizada.*;
import simulacao.Config;

public var contadorGeral = 0;
public var vetorDeAntecipacaoDeColisao: VetorColisao = VetorColisao.inicializa(SimulationView.cenarioCorrente.veiculos.size());

public function simulationUpdate(): Void {

    contadorGeral++;

//    for (veiculo in SimulationView.cenarioCorrente.veiculos) {
//        escreverSaida(veiculo.imprimirDados());
//    }

//    escreverSaida(vetorDeAntecipacaoDeColisao);
//    escreverSaida("***********************************************");

    escreverSaida("=====================================================================================\n"
//                  "                   [{contadorGeral}] - Veiculo: {veiculoAtual.idVeiculo}\n"
                  "                                    [{contadorGeral}]\n"
                  "=====================================================================================\n");

    for (veiculoAtual in reverse SimulationView.cenarioCorrente.veiculos) {

//        if (veiculoAtual.visible) {
//
//            veiculoAtual.verificarTrocaDeFaixaDeRodagem();
//            verificarColisao(veiculoAtual);
//            veiculoAtual.verificarAjusteDeVelocidade();
//            verificarSeVeiculoNovoPodeSerExibido(veiculoAtual);
//
//        } else {


//            escreverSaida(veiculoAtual.imprimirDados());

            // Verifica se o veiculo quer e pode trocar de faixa
//            escreverSaida("--------------------------------------------------------------\n"
//                          "1) Verificando se o veiculo quer e pode trocar de faixa\n"
//                          "--------------------------------------------------------------");
            veiculoAtual.verificarTrocaDeFaixaDeRodagem();
//            escreverSaida("--------------------------------------------------------------\n");


            // Verifica se o veiculo esta colidindo
//            escreverSaida("--------------------------------------------------------------\n"
//                          "2) Verificando se o veiculo esta colidindo\n"
//                          "--------------------------------------------------------------");
            verificarColisao(veiculoAtual);
//            escreverSaida("--------------------------------------------------------------\n");

            // Verifica se um ajuste de velocidade eh necessario para os veiculos
//            escreverSaida("--------------------------------------------------------------\n"
//                          "3) Verificando se um ajuste de velocidade é necessario para o veiculo\n"
//                          "--------------------------------------------------------------");
            veiculoAtual.verificarAjusteDeVelocidade();
//            escreverSaida("--------------------------------------------------------------\n");

            // Verifica se um existe um novo veiculo que foi inserido e ainda nao esta sendo exibido
//            escreverSaida("--------------------------------------------------------------\n"
//                          "4) Verificando se um existe um novo veiculo que foi inserido e ainda nao esta sendo exibido\n"
//                          "--------------------------------------------------------------");
            verificarSeVeiculoNovoPodeSerExibido(veiculoAtual);
//            escreverSaida("--------------------------------------------------------------\n");

        }
        
        escreverSaida("*************************************************************************************************************\n"
                      "*************************************************************************************************************\n\n");
//    }
}

function verificarSeVeiculoNovoPodeSerExibido(veiculo: Veiculo) {

    if (not veiculo.visible) {

        escreverSaida("Veiculo {veiculo.idVeiculo} nao esta visivel...");

        if (veiculo.quantidadeLoopsParaFicarVisivel > 0) {
            escreverSaida("Veiculo {veiculo.idVeiculo} ainda tem que esperar {veiculo.quantidadeLoopsParaFicarVisivel} loops até que fique visivel");
            veiculo.quantidadeLoopsParaFicarVisivel--;

        } else if (veiculo.idVeiculoSobreposto != VetorColisao.NULL) {
            escreverSaida("Veiculo {veiculo.idVeiculo} ESTÁ se sobrepondo com o Veiculo {veiculo.idVeiculoSobreposto}... ainda nao sera exibido... =(");

        } else {
            escreverSaida("Veiculo {veiculo.idVeiculo} nao esta se sobrepondo... passará a ser exibido... =D");
            veiculo.visible = true;
            SimulationView.cenarioCorrente.veiculoRecemAdicionado = veiculo;
        }
    }
}

function verificarColisao(veiculoAtual: Veiculo): Void {

    // Verificar colisao frontal com outros veiculos e subidas.

    // Para resolver caso de colisao onde a antecipacao nao foi capaz de resolver. Impedir que o veiculo passee um pelo outro
    var boundsVeiculoAtual = veiculoAtual.boundingBoxVeiculo.localToScene(veiculoAtual.boundingBoxVeiculo.boundsInLocal);
    var frontalBoundsVeiculoAtual = veiculoAtual.boundingBoxFrontal.localToScene(veiculoAtual.boundingBoxFrontal.boundsInLocal);
    var tratarNaoColisaoFrontal = false;

    for (veiculoComparado in SimulationView.cenarioCorrente.veiculos) {

        var boundsVeiculoComparado = veiculoComparado.boundingBoxVeiculo.localToScene(veiculoComparado.boundingBoxVeiculo.boundsInLocal);

        if (veiculoAtual.idVeiculo != veiculoComparado.idVeiculo) {

            /**************************** Verifica a colisao frontal e impede que um veiculo passe por cima do outro ***************************/
            if (boundsVeiculoAtual.intersects(boundsVeiculoComparado)
                    and veiculoAtual.faixaDeRodagemAtual == veiculoComparado.faixaDeRodagemAtual
                    and vetorDeAntecipacaoDeColisao.setarColisao(veiculoAtual.idVeiculo, veiculoComparado.idVeiculo)) {

                escreverSaida("\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
                escreverSaida("Veiculo {veiculoAtual.idVeiculo} colidiu com sobreposicao com Veiculo {veiculoComparado.idVeiculo}...");
                escreverSaida("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");

                tratarSobreposicaoDoVeiculo(veiculoAtual, veiculoComparado);
                tratarNaoColisaoFrontal = false;
                break;


                /*************************************** Verifica a antecipacao de colisao frontal *************************************************/
            } else if (frontalBoundsVeiculoAtual.intersects(boundsVeiculoComparado)
                    and veiculoAtual.faixaDeRodagemAtual == veiculoComparado.faixaDeRodagemAtual
                    and vetorDeAntecipacaoDeColisao.setarColisao(veiculoAtual.idVeiculo, veiculoComparado.idVeiculo)) {

//                escreverSaida("\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
//                escreverSaida("Veiculo {veiculoAtual.idVeiculo} colidiu com Veiculo {veiculoComparado.idVeiculo}...");
//                escreverSaida("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");

                tratarColisaoDoVeiculo(veiculoAtual, veiculoComparado);
                tratarNaoColisaoFrontal = false;
                break;

            } else {
                tratarNaoColisaoFrontal = true;
            }
        }
    }

    if (tratarNaoColisaoFrontal) {
        tratarNaoColisaoDoVeiculo(veiculoAtual);
        }

    // Usado para ver quanto tempo o veiculo nao tentou trocar de faixa, ou trocou  com sucesso
    veiculoAtual.quantidadeNaoColisoesLaterais++;

    /*************************************** Verificar se os veiculos estao em subida ***************************************/
    if (veiculoAtual.boundsInParent.intersects(SimulationView.cenarioCorrente.pista.regiaoElevacao.boundsInParent)) {

        if (veiculoAtual.isAntecipandoColisao()) {
            // Nesse momento sua velocidade alvo ja eh a velociodade do veiculo da frente...
            veiculoAtual.velocidadeAlvo = Math.min(veiculoAtual.velocidadeAlvo, veiculoAtual.velocidadeEmSubida);

        } else {
            veiculoAtual.velocidadeAlvo = veiculoAtual.velocidadeEmSubida;
        }
    }
    /*************************************************************************************************************************/
}

function tratarNaoColisaoDoVeiculo(veiculo: Veiculo) {

//    escreverSaida("Tratando NAO colisao do veiculo [{veiculo.idVeiculo}]");
    veiculo.quantidadeNaoColisoesFrontais++;

    // Artificio utilizado para dar uma margem de seguranca para nao deteccao de colisao.
    if (veiculo.isNOTAntecipandoColisao()) {

        // O veiculo tem pista livre pela frente
        // A velocidade Alvo desse veiculo passa a ser a sua velocidade em pista livre
        veiculo.velocidadeAlvo = veiculo.velocidadeEmPistaLivre;
        veiculo.quantidadeColisoesFrontais = 0;
        vetorDeAntecipacaoDeColisao.limparColisao(veiculo.idVeiculo);
    }
        
    veiculo.idVeiculoSobreposto = VetorColisao.NULL;
}

function tratarColisaoDoVeiculo(veiculoAutorDaColisao: Veiculo, veiculoReceptorDaColisao: Veiculo) {

    if (veiculoAutorDaColisao.quantidadeTentativasTrocarDeFaixa == 0 and
        veiculoAutorDaColisao.indiceDeAgressividade > Util.random(Config.INDICE_AGRESSIVIDADE_MAXIMO + 1)) {

        escreverSaida("Veiculo [{veiculoAutorDaColisao.idVeiculo}] irá trocar de faixa assim que possível");
        veiculoAutorDaColisao.trocarDeFaixaAssimQuePossivel = true

    } else {

        escreverSaida("Tratando colisao do veiculo [{veiculoAutorDaColisao.idVeiculo}] com [{veiculoReceptorDaColisao.idVeiculo}]");

        veiculoAutorDaColisao.quantidadeColisoesFrontais++;
        veiculoAutorDaColisao.quantidadeNaoColisoesFrontais = 0;

        // Se o carro estiver desacelerando, nao vou interferir na sua velocidade, vou deixa-lo terminar seu processo de desaceleracao
        if (not veiculoAutorDaColisao.isDesacelerando()) {
            veiculoAutorDaColisao.velocidadeAlvo = veiculoReceptorDaColisao.velocidadeAlvo;
        }
    }
    
    veiculoAutorDaColisao.idVeiculoSobreposto = VetorColisao.NULL;;
    
}

function tratarSobreposicaoDoVeiculo(veiculoAutorDaColisao: Veiculo, veiculoReceptorDaColisao: Veiculo) {
    escreverSaida("Tentando desfazer erro de sobreposicao de veiculos [{veiculoAutorDaColisao.idVeiculo}] com [{veiculoReceptorDaColisao.idVeiculo}]");

    veiculoAutorDaColisao.quantidadeColisoesFrontais++;
    veiculoAutorDaColisao.quantidadeNaoColisoesFrontais = 0;

    veiculoAutorDaColisao.idVeiculoSobreposto = veiculoReceptorDaColisao.idVeiculo;
    veiculoAutorDaColisao.velocidadeAlvo = veiculoReceptorDaColisao.velocidadeAlvo * 0.8;
}

public function alternarPlayPause() {
    if (SimulationView.simulacaoExecutando) {
        SimulationView.simulacaoExecutando = false;
        pauseGame();

    } else {
        SimulationView.simulacaoExecutando = true;
        playGame();
    }
}

function playGame() {
    Main.simulationLoop.play();
    SimulationView.cenarioCorrente.play();
    Main.threadEscrita.flush();
}

function pauseGame(): Void {
    SimulationView.cenarioCorrente.pause();
    Main.simulationLoop.pause();
}
